package com.es.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.es.dto.SkuDTO;
import com.es.dto.SpecParamDTO;
import com.es.dto.SpuDTO;
import com.es.dto.SpuDetailDTO;
import com.es.entity.Goods;

import com.es.entity.goods.TbBrand;
import com.es.entity.goods.TbCategory;
import com.es.entity.goods.TbSku;
import com.es.entity.goods.TbSpecParam;
import com.es.entity.goods.TbSpu;
import com.es.entity.goods.TbSpuDetail;
import com.es.repository.GoodsRepository;
import com.es.service.TbBrandService;
import com.es.service.TbCategoryService;
import com.es.service.TbSpecParamService;
import com.es.service.TbSpuDetailService;
import com.es.service.TbSpuService;
import com.es.service.GoodsService;
import com.es.service.SearchService;
import com.es.service.TbSkuService;
import com.es.utils.BeanHelper;
import com.es.utils.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Service
public class GoodsServiceImpl implements GoodsService {

    @Resource
    private TbSpuService tbSpuService;

    @Autowired
    private TbBrandService tbBrandService;
    @Autowired
    private TbCategoryService tbCategoryService;

    @Autowired
    private TbSpecParamService specParamService;

    @Autowired
    private SearchService searchService;
    @Autowired
    private GoodsRepository goodsRepository;


    @Autowired
    private TbSpuDetailService tbSpuDetailService;
    @Autowired
    private TbSkuService tbSkuService;

    @Override
    public void save() {
        int page = 1;
        int size = 50;
        while (true){
            //获取spuDTO
            List<SpuDTO> spuDTOList = this.findspuByPage(page, size, null,true);
            if (CollectionUtil.isEmpty(spuDTOList)){

            }
            //获取goods对象
            List<Goods> goodsList = new ArrayList<>();
            for (SpuDTO spuDTO : spuDTOList) {
                Goods goods = this.createGoods(spuDTO);
                //System.out.println(goods);
                goodsList.add(goods);
            }
            //把goods对象写入es
            goodsRepository.saveAll(goodsList);
            if(spuDTOList.size() < size){
                break;
            }
            page++;
        }
    }

    public Goods createGoods(SpuDTO spuDTO){
        Long spuId = spuDTO.getId();
        //存放全文检索的内容all ,name ,brandName,categoryName
        String all = spuDTO.getName() + "," + spuDTO.getBrandName() + "," + spuDTO.getCategoryName();
        //远程调用 获取sku的集合
        List<SkuDTO> skuDTOList = this.findSkuListBySpuId(spuId);
        //创建集合重新存
        List<Map<String, Object>> skuMaplist = new ArrayList<>();
        //创建价格
        Set<Long> price = new HashSet<>();
        for (SkuDTO skuDTO : skuDTOList) {
            Map<String, Object> map = new HashMap<>();
            map.put("id",skuDTO.getId());
            map.put("price",skuDTO.getPrice());
            map.put("image", StringUtils.substringBefore(skuDTO.getImages(),","));
            map.put("title",skuDTO.getTitle());
            //保存sku
            skuMaplist.add(map);
            //保存价格
            price.add(skuDTO.getPrice());
        }
        //转JSON
        String skuListJson = JSONObject.toJSONString(skuMaplist);

        //根据cid查询Spec
        List<SpecParamDTO> ParamDTOList = specParamService.findSpecParamByGid(null, spuDTO.getCid3(), true);
        //根据spuid查询详情
        SpuDetailDTO detailDTO = this.findDetailById(spuId);
        //获取通用的参数
        String genericSpec = detailDTO.getGenericSpec();
        Map<Long, Object> genericMap = JsonUtils.toMap(genericSpec, Long.class, Object.class);
        //获取特有的参数
        String specialSpec = detailDTO.getSpecialSpec();
        Map<Long,List<String>> specialMap = JsonUtils.nativeRead(specialSpec, new TypeReference<Map<Long,List<String>>>() {
        });
        //储存specs
        Map<String,Object> specsMap = new HashMap<>();
        for (SpecParamDTO paramDTO : ParamDTOList) {
            Long id = paramDTO.getId();
            String key = paramDTO.getName();
            Object val = null;
            if(paramDTO.getGeneric()){
                val = genericMap.get(id);
            }else {
                val = specialMap.get(id);
            }
            if(paramDTO.getIsNumeric()){
                val = this.chooseSegment(val, paramDTO);
            }
            specsMap.put(key,val);
        }
        Goods goods = new Goods();
        goods.setId(spuId);
        goods.setCategoryId(spuDTO.getCid3());
        goods.setBrandId(spuDTO.getBrandId());
        goods.setCreateTime(spuDTO.getCreateTime().getTime());
        goods.setSubTitle(spuDTO.getSubTitle());

        goods.setAll(all);

        goods.setPrice(price);
        goods.setSkus(skuListJson);

        goods.setSpecs(specsMap);
        return goods;
    }
    private String chooseSegment(Object value, SpecParamDTO p) {
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 查询spu列表
     *
     * @param page
     * @param rows
     * @param key
     * @param saleable
     * @return
     */
    public List<SpuDTO> findspuByPage(Integer page, Integer rows, String key, Boolean saleable) {
        Page<TbSpu> tbSpuPage = new Page<>(page, rows);
        //查询的条件
        QueryWrapper<TbSpu> queryWrapper = new QueryWrapper<>();
        //模糊查询
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.lambda().like(TbSpu::getName, key);
        }
        //是否上架
        if (saleable != null) {
            queryWrapper.lambda().eq(TbSpu::getSaleable, saleable);
        }
        //进行排序
        queryWrapper.lambda().orderByDesc(TbSpu::getUpdateTime);

        //分页查询
        IPage<TbSpu> tbSpuIPage = tbSpuService.page(tbSpuPage, queryWrapper);
        List<TbSpu> tbSpuList = tbSpuIPage.getRecords();
        if (CollectionUtils.isEmpty(tbSpuList)) {
            throw new IndexOutOfBoundsException();
        }
        //转bean
        List<SpuDTO> spuDTOList = BeanHelper.copyWithCollection(tbSpuList, SpuDTO.class);
        //处理 品牌名称和分类名称
        handlerCategoryNameAndBrandName(spuDTOList);

        return spuDTOList;
    }

    private void handlerCategoryNameAndBrandName(List<SpuDTO> spuDTOList) {
        for (SpuDTO spuDTO : spuDTOList) {
            Long brandId = spuDTO.getBrandId();
            TbBrand tbBrand = tbBrandService.getById(brandId);
            spuDTO.setBrandName(tbBrand.getName());

            //处理3级分类的名字
            String cname = "";
            Collection<TbCategory> tbCategoryCollection = tbCategoryService.listByIds(spuDTO.getCategoryIds());
              /*for (TbCategory tbCategory : tbCategoryCollection) {
                if(cname.length()>0){
                    cname += "/";
                }
                cname += tbCategory.getName();
            }*/
            cname = tbCategoryCollection.stream().map(TbCategory::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(cname);
        }
    }

    /**
     * 保存商品
     * @param spuDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveGoods(SpuDTO spuDTO) {
        //保存spu信息
        TbSpu tbSpu = BeanHelper.copyProperties(spuDTO, TbSpu.class);
        boolean b = tbSpuService.save(tbSpu);
        if(!b){
            throw new IndexOutOfBoundsException();
        }
        Long spuId = tbSpu.getId();
        //保存详情表
        SpuDetailDTO spuDetail = spuDTO.getSpuDetail();
        TbSpuDetail tbSpuDetail = BeanHelper.copyProperties(spuDetail, TbSpuDetail.class);
        tbSpuDetail.setSpuId(spuId);
        //保存spudetail信息
        boolean b1 = tbSpuDetailService.save(tbSpuDetail);
        if(!b1){
            throw new IndexOutOfBoundsException();
        }
        //保存sku信息

        List<SkuDTO> skus = spuDTO.getSkus();
        List<TbSku> tbSkuList = BeanHelper.copyWithCollection(skus, TbSku.class);
        for (TbSku tbSku : tbSkuList) {
            tbSku.setSpuId(spuId);
        }
        boolean b2 = tbSkuService.saveBatch(tbSkuList);
        if(!b2){
            throw new IndexOutOfBoundsException();
        }
    }
    /**
     * 修改商品的上下架
     * @param gid
     * @param saleable
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuSaleable(Long gid, Boolean saleable) {
        //更新spu表
        TbSpu tbSpu = new TbSpu();
        tbSpu.setId(gid);
        tbSpu.setSaleable(saleable);
        boolean b = tbSpuService.updateById(tbSpu);
        if(!b){
            throw new IndexOutOfBoundsException();
        }
        //更新sku表
        UpdateWrapper<TbSku> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(TbSku::getSpuId,gid);
        updateWrapper.lambda().set(TbSku::getEnable,saleable);
        boolean b1 = tbSkuService.update(updateWrapper);
        if(!b1){
            throw new IndexOutOfBoundsException();
        }
    }
    /**
     * 根据spuid查询detail
     * @param id
     * @return
     */
    public SpuDetailDTO findDetailById(Long id) {
        TbSpuDetail spuDetail = tbSpuDetailService.getById(id);
        if(spuDetail == null){
            throw new IndexOutOfBoundsException();
        }
        return BeanHelper.copyProperties(spuDetail,SpuDetailDTO.class);
    }
    /**
     * 根据spuid查询sku
     * @param id
     * @return
     */
    public List<SkuDTO> findSkuListBySpuId(Long id) {
        QueryWrapper<TbSku> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TbSku::getSpuId,id);
        List<TbSku> tbSkuList = tbSkuService.list(queryWrapper);
        if(CollectionUtils.isEmpty(tbSkuList)){
            throw new IndexOutOfBoundsException();
        }
        return BeanHelper.copyWithCollection(tbSkuList,SkuDTO.class);
    }

    /**
     * 修改商品
     * @param spuDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateGoods(SpuDTO spuDTO) {
        Long spuId = spuDTO.getId();
        //修改spu
        TbSpu tbSpu = BeanHelper.copyProperties(spuDTO, TbSpu.class);
        boolean b = tbSpuService.updateById(tbSpu);
        if (!b){
            throw new IndexOutOfBoundsException();
        }
        //修改detail
        SpuDetailDTO spuDetail = spuDTO.getSpuDetail();
        TbSpuDetail tbSpuDetail = BeanHelper.copyProperties(spuDetail, TbSpuDetail.class);
        boolean b1 = tbSpuDetailService.updateById(tbSpuDetail);
        if(!b1){
            throw new IndexOutOfBoundsException();
        }
        //先删除sku
        QueryWrapper<TbSku> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TbSku::getSpuId,spuId);
        boolean b2 = tbSkuService.remove(queryWrapper);
        if(b2){
            throw new IndexOutOfBoundsException();
        }
        //更新sku
        List<SkuDTO> skus = spuDTO.getSkus();
        List<TbSku> tbSkuList = BeanHelper.copyWithCollection(skus, TbSku.class);
        for (TbSku tbSku : tbSkuList) {
            tbSku.setSpuId(spuId);
        }
        boolean b3 = tbSkuService.saveBatch(tbSkuList);
        if(!b3){
            throw new IndexOutOfBoundsException();
        }
    }
    /**
     *根据主键查询spu
     * @param spuId
     * @return
     */
    public SpuDTO findSpuById(Long spuId) {
        TbSpu tbSpu = tbSpuService.getById(spuId);
        if(tbSpu == null){
            throw new IndexOutOfBoundsException();
        }
        return BeanHelper.copyProperties(tbSpu,SpuDTO.class);
    }

}
